package com.example.forum.services.impl;

import com.example.forum.common.AppResult;
import com.example.forum.common.ResultCode;
import com.example.forum.dao.UserMapper;
import com.example.forum.exception.ApplicationException;
import com.example.forum.model.User;
import com.example.forum.services.UserService;
import com.example.forum.utils.MD5Util;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;


@Slf4j
@Service
public class UserServiceImpl implements UserService {

    /**
     * 这里存在一些复杂的调用关系
     * controller ->  services  -> mapper
     * mapper是接口，里面定义了函数的样式，具体实现在对应的xml文件里面，写法相对固定
     * controller ->  services 因为两者存在调用的关系，也就意味着，
     * 一些代码可以写在controller里面，也可以写在services里面，
     * services层的函数可以被多个controller的函数调用，
     * 如果services的函数写得少了，那么controller的多个函数就可能出现重复代码，代码的复用就会降低
     * 如果services的函数写得多了，那么就可能导致不能被多个controller的函数调用，也会降低代码的复用
     * 那具体该怎么判断写在哪里呢？这就跟controller层以及services的职责有关了
     */

    /**
     * 确实，有时候业务逻辑可以被放在服务（`services`）层，也可以被放在控制器（`controllers`）层。这种情况下，很可能是因为业务逻辑较为简单，没有涉及到复杂的处理流程或数据操作。在这种情况下，选择将业务逻辑写在哪一层往往是主观的，并且可以根据具体项目的需求和团队的偏好来决定。
     * 一般来说，有一些指导原则可以帮助你做出决策：
     * 1. **单一职责原则：** 控制器应该专注于接收和处理 HTTP 请求，并将业务逻辑委托给服务。服务应该专注于执行业务逻辑，而映射器（`mappers`）应该专注于与数据存储的交互。
     * 2. **业务逻辑的复杂性：** 如果业务逻辑相对简单，没有复杂的处理流程，那么它们可能放在控制器中更为合适。但是，一旦业务逻辑变得复杂，建议将其放在服务层，以便更好地组织和测试。
     * 3. **代码复用性：** 如果业务逻辑可能在多个控制器之间共享，或者将来可能被其他部分重用，将其放在服务层可能更有利于代码的复用。
     * 4. **测试：** 将业务逻辑放在服务层可以更容易进行单元测试。控制器层的测试通常会涉及到模拟 HTTP 请求和检查 HTTP 响应，而服务层可以更直接地进行业务逻辑的单元测试。
     * 总体来说，选择将业务逻辑放在哪一层取决于具体的项目需求和开发团队的偏好。重要的是要保持一致性，并确保整个团队都了解和遵循相同的设计原则。
     */

    @Resource
    private UserMapper userMapper;

    /**
     * 注册普通用户————User
     * @param user
     */
    @Override
    public void createNormalUser(User user) {
        //如果用户名已经存在则注册失败
        if(userMapper.selectByUserName(user.getUsername())!=null){
            log.info("该用户名已存在！");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
        }else{
            if (user.getGender() == null) {
                //性别赋默认值
                user.setGender((byte) 2);
            }
            //填充默认值
            user.setIsAdmin((byte) 0);
            user.setAvatarUrl(null);
            user.setArticleCount(0);
            user.setState((byte) 0);
            user.setDeleteState((byte) 0);
            Date date = new Date();
            user.setCreateTime(date);
            user.setUpdateTime(date);
            //调用mapper,完成业务
            int row = userMapper.insertSelective(user);
            if(row!=1){
                log.info(ResultCode.FAILED_CREATE.toString()+"username"+user.getUsername());
                throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
            }
            log.info("新增用户成功：username = "+user.getUsername());
        }

    }

    /**
     * 根据用户名查询用户————username
     * @param username
     * @return
     */
    @Override
    public User selectByUserName(String username) {
        //调用mapper,完成业务
        return userMapper.selectByUserName(username);
    }


    /**
     * 登录功能————username、password
     * @param username ⽤⼾名
     * @param password 密码
     * @return
     */
    @Override
    public User login(String username, String password) {
        //调用mapper,完成业务
        //1，根据用户名查询用户，用户不存在登陆失败，用户存在则比较两个密码是否一致
        User user = userMapper.selectByUserName(username);
        String encryptPassword = MD5Util.md5Salt(password, user.getSalt());
        if (!encryptPassword.equalsIgnoreCase(user.getPassword())) {
            //记录⽇志
            log.info(ResultCode.FAILED_LOGIN.toString() + "username = " + username
                    + ", password = " + password);
            //密码不正确抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        //校验通过，返回⽤⼾信息
        //2，根据用户名和密码查询用户，查询成成功即可登录！
        return user;
    }


    /**
     * 根据用户id查询用户————用户id
     * @param Id
     * @return
     */
    @Override
    public User selectById(Long Id) {
        return userMapper.selectByPrimaryKey(Id);
    }


    /**
     * 修改个人信息————User
     * @param user
     * @return
     */
    @Override
    public int modifyInfo(User user) {
        return userMapper.updateByPrimaryKeySelective(user);
    }

    /**
     * 修改密码————(这个参数设计的不是很好！)
     * @param id
     * @param newPassword
     * @param oldPassword
     * @return
     */
    @Override
    public int modifyPassword(Long id, String newPassword, String oldPassword) {
        User user = userMapper.selectByPrimaryKey(id);

        String oldEncryptPassword = MD5Util.md5Salt(oldPassword, user.getSalt());
        if(!oldEncryptPassword.equals(user.getPassword())){
            //旧密码错误，不允许修改
            return -1;
        }
        String newEncryptPassword = MD5Util.md5Salt(newPassword, user.getSalt());
        user.setPassword(newEncryptPassword);
        return  userMapper.updateByPrimaryKeySelective(user);

    }

    /**
     * 用户的文章数量增加
     * @param id
     * @return
     */
    @Override
    public int addOneArticleCountById(Long id) {
        User newUser = userMapper.selectByPrimaryKey(id);
        newUser.setArticleCount(newUser.getArticleCount()+1);
        userMapper.updateByPrimaryKeySelective(newUser);
        return 0;
    }

    /**
     * 用户的文章数量减少
     * @param id
     */
    @Override
    public void subOneArticleCountById(Long id) {
        User newUser = userMapper.selectByPrimaryKey(id);
        newUser.setArticleCount(newUser.getArticleCount()-1);
        userMapper.updateByPrimaryKeySelective(newUser);
    }

}
